<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>PyQt4 Widgets</title>
<link rel="stylesheet" href="../format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyQt, PyQt4, Widgets, Controls, tutorial, Python, Linux">
<meta nam="description" content="Widgets">
<meta name="language" content="de">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">
<meta name="translation" content="manuel stein">
</head>

<body>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href=".." title="Home">Contents</a>


<h1>PyQt4 Widgets</h1>


<p>
Widgets sind die grundlegenden Bausteine einer Anwendung. Das PyQt4-Programmier-Toolkit 
verfügt über eine breite Auswahl verschiedener Widgets: Knöpfe, Auswahlboxen, 
Schiebregler, Listenboxen <abbr title="et cetera">etc.</abbr> - Alles, was ein 
Programmierer für seinen Job braucht. In diesem Abschnitt des Tutorials, 
werden wir einige nützliche Widgets vorstellen.
</p>


<h3>QCheckBox</h3>

<p>
<em>QCheckBox</em> ist ein Widget mit zwei Zuständen: An und Aus. Es besteht aus einer 
Box und einem Label. Immer wenn eine Auswahlbox angehakt oder geleert wird, wirft sie das Signal <em>stateChanged()</em>.
</p>

<pre class="code">
#!/usr/bin/python

# checkbox.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class CheckBox(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Checkbox')

        self.cb = QtGui.QCheckBox('Show title', self)
        self.cb.setFocusPolicy(QtCore.Qt.NoFocus)
        self.cb.move(10, 10)
        self.cb.toggle();
        self.connect(self.cb, QtCore.SIGNAL('stateChanged(int)'), self.changeTitle)

    def changeTitle(self, value):
        if self.cb.isChecked():
            self.setWindowTitle('Checkbox')
        else:
            self.setWindowTitle('')

app = QtGui.QApplication(sys.argv)
icon = CheckBox()
icon.show()
app.exec_()
</pre>

<p>
In unserem Beispiel werden wir eine Auswahlbox erstellen, die den Fenstertitel einstellt.
</p>

<pre class="explanation">
 self.cb = QtGui.QCheckBox('Show title', self)
</pre>

<p>
Das ist der <em>QCheckBox</em>-Konstruktor.
</p>

<pre class="explanation">
 self.cb.setFocusPolicy(QtCore.Qt.NoFocus)
</pre>

<p>
Wir verbinden die zuvor erstellte Methode <em>changeTitle()</em> mit dem <em>stateChanged()</em>-Signal.
Die <em>changeTitle()</em>-Methode stellt den Fenstertitel um.
</p>

<pre class="explanation">
 self.connect(self.cb, QtCore.SIGNAL('stateChanged(int)'), self.changeTitle)
</pre>

<p>
Standardmäßig lässt sich die <em>QCheckbox</em> fokussieren. Dies geschieht durch ein dünnes 
Rechteck um das Label der Auswahlbox herum, das jedoch so schrecklich aussieht, dass ich es 
lieber deaktiviere, indem ich die Widget-Fokuseinstellung auf <em>Qt.NoFocus</em> setze.
</p>


<pre class="explanation">
 self.cb.toggle();
</pre>

<p>
Wir setzen den Fenstertitel, also müssen wir die Auswahlbox anhaken. Standardmäßig ist der
Fenstertitel nicht gesetzt und die Auswahlbox leer.
</p>

<img src="../images/checkbox.jpg" alt="QCheckBox">
<p class="figure">Abbildung: QCheckBox</p>


<h3>Umschaltknopf</h3>

<p>
PyQt4 verfügt über kein eigenes Widget für einen Umschaltknopf. Um einen solchen zu erzeugen, 
verwenden wir einen <em>QPushButton</em> in einem speziellen Modus. 
Ein Umschaltknopf ist ein Knopf mit zwei Zuständen: Gedrückt und <q>ungedrückt</q>. 
Sie können zwischen den Zuständen wechseln, indem auf den Knopf klicken. Es gibt Situationen, 
in denen diese Funktionsweise genau das ist, was man braucht.
</p>

<pre class="code">
#!/usr/bin/python

# togglebutton.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class ToggleButton(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.color = QtGui.QColor(0, 0, 0) 

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('ToggleButton')

        self.red = QtGui.QPushButton('Red', self)
        self.red.setCheckable(True)
        self.red.move(10, 10)

        self.connect(self.red, QtCore.SIGNAL('clicked()'), self.setRed)

        self.green = QtGui.QPushButton('Green', self)
        self.green.setCheckable(True)
        self.green.move(10, 60)

        self.connect(self.green, QtCore.SIGNAL('clicked()'), self.setGreen)

        self.blue = QtGui.QPushButton('Blue', self)
        self.blue.setCheckable(True)
        self.blue.move(10, 110)

        self.connect(self.blue, QtCore.SIGNAL('clicked()'), self.setBlue)

        self.square = QtGui.QWidget(self)
        self.square.setGeometry(150, 20, 100, 100)
        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks'))

    def setRed(self):
        if self.red.isChecked():
            self.color.setRed(255)
        else: self.color.setRed(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

    def setGreen(self):
        if self.green.isChecked():
            self.color.setGreen(255)
        else: self.color.setGreen(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

    def setBlue(self):
        if self.blue.isChecked():
            self.color.setBlue(255)
        else: self.color.setBlue(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())



app = QtGui.QApplication(sys.argv)
tb = ToggleButton()
tb.show()
app.exec_()
</pre>

<p>
In unserem Beispiel erzeugen wir drei Umschaltknöpfe. Darüber hinaus erzeugen wir ein <em>QWidget</em>, 
dessen Hintergrundfarbe wir auf Schwarz setzen. Die Umschaltknöpfe ändern die Rot-, 
Grün- und Blauanteile des Farbwertes. Das heißt, die Hintergrundfarbe hängt davon ab, welche Umschaltknöpfe wir drücken.
</p>

<pre class="explanation">
 self.color = QtGui.QColor(0, 0, 0)
</pre>

<p>
Das ist der Startwert der Farbe: Kein Rot, kein Grün und kein Blau ergeben Schwarz. 
Theoretisch ausgedrückt handelt es sich bei Schwarz nicht um eine Farbe, sondern vielmehr um <q>Keine Farbe</q>.
</p>

<pre class="explanation">
 self.red = QtGui.QPushButton('Red', self)
 self.red.setCheckable(True)
</pre>

<p>
Um einen Umschaltknopf zu erzeugen, erzeugen wir einen <em>QPushButton</em> und machen ihn 
auswählbar, indem wir die <em>setCheckable</em>-Methode aufrufen.
</p>

<pre class="explanation">
 self.connect(self.red, QtCore.SIGNAL('clicked()'), self.setRed)
</pre>

<p>
Wir verbinden ein <em>clicked()</em>-Signal mit unserer selbst erstellten Methode.
</p>

<pre class="explanation">
 QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks'))
</pre>

<p>
Ich habe den Style der Applikation auf <em>cleanlooks</em> gestellt, da der Standardstyle 
unter Linux (Plastique) einen Design-Fehler hat. Dort kann man nicht einfach festlegen, 
ob der Umschaltknopf gedrückt ist oder nicht. Das geht unter CleanLooks besser.
</p>

<pre class="explanation">
 if self.red.isChecked():
     self.color.setRed(255)
 else: self.color.setRed(0)
</pre>

<p>
Wir prüfen, ob der Knopf gedrückt wurde und der Farbwert entsprechend angepasst wurde.
</p>

<pre class="explanation">
 self.square.setStyleSheet("QWidget { background-color: %s }" % self.color.name())
</pre>

<p>
Um die HIntergrundfarbe zu ändern, verwenden wir Stylesheets.
</p>

<img src="../images/togglebutton.jpg" alt="Umschaltknopf">
<p class="figure">Abbildung: Umschaltknopf</p>

<h3>QSlider, QLabel</h3>

<p>
QSlider ist ein Widget, das über einen einfachen Anfasser verfügt. Der Anfasser kann 
vor und zurück gezogen werden. Auf diese Weise wählen wir einen Wert zu einem bestimmten Zweck. 
Manchmal ist ein solcher Schiebregler viel natürlicher als einfach eine Zahl zu übergeben oder einen Drehschalter zu verwenden.
QLabel zeigt einen Text oder ein Bild an.
</p>

<p>
In unserem Beispiel verwenden wir einen Regler und ein Label. Diesmal wird mit dem Label ein Bild angezeigt und über den Regler kontrolliert.
</p>

<pre class="code">
#!/usr/bin/python

# slider-label.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class SliderLabel(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('SliderLabel')

        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
        self.slider.setGeometry(30, 40, 100, 30)
        self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)


        self.label = QtGui.QLabel(self)
        self.label.setPixmap(QtGui.QPixmap('mute.png'))
        self.label.setGeometry(160, 40, 80, 30)


    def changeValue(self, value):
        pos = self.slider.value()

        if pos == 0:
            self.label.setPixmap(QtGui.QPixmap('mute.png'))
        elif pos > 0 and pos <= 30:
            self.label.setPixmap(QtGui.QPixmap('min.png'))
        elif pos > 30 and pos < 80:
            self.label.setPixmap(QtGui.QPixmap('med.png'))
        else:
            self.label.setPixmap(QtGui.QPixmap('max.png'))

app = QtGui.QApplication(sys.argv)
icon = SliderLabel()
icon.show()
app.exec_()
</pre>

<p>
In unserem Beispiel simulieren wir einen Lautstärkeregler. Durch Ziehen des Anfassers verändern wir das Bild des Labels.
</p>

<pre class="explanation">
 self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
</pre>

<p>
Hier erzeugen wir einen waagerechten <em>QSlider</em>.
</p>

<pre class="explanation">
 self.label = QtGui.QLabel(self)
 self.label.setPixmap(QtGui.QPixmap('mute.png'))
</pre>

<p>
Wir erzeugen ein <em>QLabel</em> und verpassen ihm ein Anfangsbild für die Stummschaltung.
</p>

<pre class="explanation">
 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
</pre>

<p>
Wir verbinden das <em>valueChanged</em>-Signal mit der selbst erstellten <em>changeValue()</em>-Methode.
</p>

<pre class="explanation">
 pos = self.slider.value()
</pre>

<p>
Wir erhalten die Positione des Schiebreglers über den Aufruf der <em>value()</em>-Methode. Wir ändern das Bild des Labels entsprechend.
</p>

<img src="../images/sliderlabel.jpg" alt="Regler und Label">
<p class="figure">Abbildung: Regler und Label</p>

<h3>QProgressBar</h3>

<p>
Ein Fortschrittsbalken ist ein Widget, das verwendet wird, wenn wir länger andauernde 
Aufgaben bearbeiten. Er ist animiert, damit der Nutzer weiß, dass unsere Aufgabe noch 
verarbeitet wird. Das <em>QProgressBar</em>-Widget bietet einen horizontalen und einen 
vertikalen Fortschrittsbalken. Die Aufgabe wird in Abschnitte unterteilt. Der Programmierer 
kann für den Balken einen Minimal- und einen Maximalwert bestimmen. Die Standartwerte sind 0 und 99.
</p>


<pre class="code">
#!/usr/bin/python

# progressbar.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class ProgressBar(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('ProgressBar')

        self.pbar = QtGui.QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)

        self.button = QtGui.QPushButton('Start', self)
        self.button.setFocusPolicy(QtCore.Qt.NoFocus)
        self.button.move(40, 80)

        self.connect(self.button, QtCore.SIGNAL('clicked()'), self.onStart)

        self.timer = QtCore.QBasicTimer()
        self.step = 0;


    def timerEvent(self, event):
        if self.step >= 100:
            self.timer.stop()
            return
        self.step = self.step + 1
        self.pbar.setValue(self.step)

    def onStart(self):
        if self.timer.isActive():
            self.timer.stop()
            self.button.setText('Start')
        else:
            self.timer.start(100, self)
            self.button.setText('Stop')


app = QtGui.QApplication(sys.argv)
icon = ProgressBar()
icon.show()
app.exec_()
</pre>

<p>
In unserem Beispiel haben wir einen horizontalen Fortschrittsbalken und einen Druckknopf, der den Balken startet und stoppt.
</p>

<pre class="explanation">
 self.pbar = QtGui.QProgressBar(self)
</pre>

<p>
<em>QProgressBar-Konstruktor.</em>
</p>

<pre class="explanation">
 self.timer = QtCore.QBasicTimer()
</pre>

<p>
Um den Fortschrittsbalken zu aktivieren, verwenden wir das Timer-Objekt.
</p>

<pre class="explanation">
 self.timer.start(100, self)
</pre>

<p>
Um das Timer-Ereignis zu auszulösen, rufen wir die <em>start()</em>-Methode aus. 
Diese Methode hat zwei Parameter: Zeitpunkt und Objekt, das die Ereignisse empfängt.
</p>

<pre class="explanation">
 def timerEvent(self, event):
     if self.step >= 100:
         self.timer.stop()
         return
     self.step = self.step + 1
     self.pbar.setValue(self.step)
</pre>

<p>
Jedes <em>QObject</em> und seine Abkömmlinge verfügen über einen <em>QObject.timerEvent</em>-Ereignishandler.
Um auf Timer-Ereignisse zu reagieren überschreiben wir den Ereignishandler.
</p>

<img src="../images/progressbar.jpg" alt="Fortschrittsbalken" />
<p class="figure">Abbildung: Fortschrittsbalken</p>

<h3>QCalendarWidget</h3>

<p>
Das <em>QCalendarWidget</em> ist ein Kalender-Widget mit Monatsansicht. 
Es erlaubt dem Benutzer, auf einfache und intuitive Weise ein Datum auszuwählen.
</p>


<pre class="code">
#!/usr/bin/python

# calendar.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class Calendar(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Calendar')

        self.cal = QtGui.QCalendarWidget(self)
        self.cal.setGridVisible(True)
        self.cal.move(20, 20)
        self.connect(self.cal, QtCore.SIGNAL('selectionChanged()'), self.showDate)


        self.label = QtGui.QLabel(self)
        date = self.cal.selectedDate()
        self.label.setText(str(date.toPyDate()))
        self.label.move(130, 260)


    def showDate(self):
        date = self.cal.selectedDate()
        self.label.setText(str(date.toPyDate()))


app = QtGui.QApplication(sys.argv)
icon = Calendar()
icon.show()
app.exec_()
</pre>

<p>
Das Beispiel umfasst ein Kalender-Widget und ein Label-Widget. Das aktuelle ausgewählte Datum wird im Label-Widget angezeigt.
</p>


<pre class="explanation">
 self.cal = QtGui.QCalendarWidget(self)
</pre>

<p>
Wir bauen ein Kalender-Widget.
</p>


<pre class="explanation">
 self.connect(self.cal, QtCore.SIGNAL('selectionChanged()'), self.showDate)
</pre>

<p>
Wenn wir mit dem Widget ein Datum auswählen, wird dadurch ein <em>selectionChanged()</em>-Signal geworfen. 
Wir verbinden diese Methode mit der benutzerdefinierten <em>showDate()</em>-Methode.
</p>


<pre class="explanation">
 def showDate(self):
     date = self.cal.selectedDate()
     self.label.setText(str(date.toPyDate()))
</pre>

<p>
Wir holen uns das gewählte Datum über Aufruf der
    <em>selectedDate()</em>-Methode. Dann wandeln wir das
Datums-Objekt in einen String um und übertragen ihn an das Label-Widget.
</p>

<img src="../images/calendar.jpg" alt="Kalender-Widget">
<p class="figure">Abbildung: Kalender-Widget</p>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 24, 2007  <span class="copyright">&copy; 2007 - 2011 Jan Bodnar</span>
<span class="copyright">Translation © 2009 Manuel Stein</span>
</div>
</div>

</div> <!-- content -->
</body>
</html>

